﻿namespace HelperLibrary;

/// <summary>
/// 对象属性复制工具列
/// </summary>
public static class MapperHelper
{
    private static readonly object _configLock = new object();
    private static bool _isConfigured = false;
    /// <summary>
    /// 将source对象的属性（同名、同类型），复制到target对象
    /// </summary>
    /// <typeparam name="T">目标类型</typeparam>
    /// <typeparam name="S">源类型</typeparam>
    /// <param name="target">目标对象</param>
    /// <param name="source">源对象</param>
    /// <returns></returns>
    public static T Mapper<T, S>(T target, S source)
    {
        if (source == null)
        {
            return target;
        }
        var spList = typeof(S).GetProperties();
        var tpList = typeof(T).GetProperties();
        foreach (PropertyInfo sp in spList)
        {
            foreach (PropertyInfo tp in tpList)
            {
                if (tp.Name == sp.Name && tp.PropertyType.Name == sp.PropertyType.Name)
                {
                    tp.SetValue(target, sp.GetValue(source));
                }
            }
        }

        return target;
    }

    /// <summary>
    /// 将source对象的属性（同名、同类型），复制到target对象，并返回新的target对象
    /// </summary>
    /// <typeparam name="T">目标类型</typeparam>
    /// <typeparam name="S">源类型</typeparam>
    /// <param name="source">源对象</param>
    /// <returns></returns>
    public static T Mapper<T, S>(S source)
    {
        if (source == null)
        {
            return default(T);
        }
        T target = Activator.CreateInstance<T>();
        var spList = typeof(S).GetProperties();
        var tpList = typeof(T).GetProperties();
        foreach (PropertyInfo sp in spList)
        {
            foreach (PropertyInfo tp in tpList)
            {
                if (tp.Name == sp.Name && tp.PropertyType.Name == sp.PropertyType.Name)
                {
                    tp.SetValue(target, sp.GetValue(source));
                }
            }
        }

        return target;
    }

    /// <summary>
    /// 将source对象列表的属性（同名、同类型），复制到target对象列表，并返回新的target对象列表
    /// </summary>
    /// <typeparam name="T">目标类型</typeparam>
    /// <typeparam name="S">源类型</typeparam>
    /// <param name="sourceList">源对象列表</param>
    /// <returns></returns>
    public static List<T> MapperList<T, S>(List<S> sourceList)
    {
        if (sourceList == null)
        {
            return default;
        }
        List<T> targetList = new List<T>();
        var spList = typeof(S).GetProperties();
        var tpList = typeof(T).GetProperties();
        foreach (var source in sourceList)
        {
            T target = Activator.CreateInstance<T>();
            foreach (PropertyInfo sp in spList)
            {
                foreach (PropertyInfo tp in tpList)
                {
                    if (tp.Name == sp.Name && tp.PropertyType.Name == sp.PropertyType.Name)
                    {
                        tp.SetValue(target, sp.GetValue(source));
                    }
                }
            }
            targetList.Add(target);
        }

        return targetList;
    }


    /// <summary>
    /// 初始化全局映射配置
    /// </summary>
    public static void Initialize(Action<TypeAdapterConfig>? configAction = null)
    {
        if (!_isConfigured)
        {
            lock (_configLock)
            {
                if (!_isConfigured)
                {
                    var config = TypeAdapterConfig.GlobalSettings;

                    // 默认配置
                    config.Default.NameMatchingStrategy(NameMatchingStrategy.Flexible);

                    // 自定义配置
                    configAction?.Invoke(config);

                    config.Compile();
                    _isConfigured = true;
                }
            }
        }
    }

    #region 基础映射方法

    public static TDest MapTo<TDest>(this object source)
    {
        return source.Adapt<TDest>();
    }

    public static TDest MapTo<TSource, TDest>(this TSource source, TDest destination)
    {
        return source.Adapt(destination);
    }

    public static List<TDest> MapToList<TDest>(this IEnumerable<object> source)
    {
        return source.Adapt<List<TDest>>();
    }

    #endregion
}
